#include "windowmanager.h"



WindowManager::WindowManager() : v_logger("window_manager.log")
{
}

WindowManager::~WindowManager(){
}



/**
*	\brief initialize the windows manager
*	\details Open a X server and computes the number of connected screens
*/
void WindowManager::start(){
    int i;
    int nb_screens;

    v_logger.log() << "The window manager is starting...";
    p_display = X11::XOpenDisplay(NULL);

    if(p_display == NULL){
        throw WindowManagerException("Error connecting to X server");
    }

    //WindowCreator::getInstance()->attachDisplay(p_display);

    // Computes the number of connected screens
    nb_screens = X11::XScreenCount(p_display);

    Screen *screen=NULL;
    // For each screen, create an associated virtual screen
    for(i=0; i<nb_screens; i++){
        screen = new Screen(i, p_display);
        v_screenList.append(screen);
    }
    p_currentScreen = screen;

    v_logger.log() << "Screens detected: " << v_screenList.count();

    //p_current_screen->getCurrentMonitor()->spawnWindow("/usr/bin/xterm");


    X11::XSetWindowAttributes wa;
    X11::Window root;
    root = X11::XRootWindow(p_display, 0);
    // Enables ConfigureRequest, MapRequest and ButtonPressed events
    wa.event_mask = SubstructureRedirectMask | ButtonPressMask | SubstructureNotifyMask ;
    X11::XChangeWindowAttributes(p_display, root, CWEventMask, &wa);
        XGrabKey(p_display, 38, AnyModifier, root, True, GrabModeAsync,
             GrabModeAsync);
}


void WindowManager::run(){

    // Creates an event and loop
    X11::XEvent ev;
    X11::XSync(p_display, False);

    m_is_running = true;

    while(m_is_running){
        X11::XNextEvent(p_display, &ev);
        switch(ev.type){
                        // A window has been created
                        case CreateNotify:
                                createNotify(&ev);
                        break;
                        // A window has been destroyed.
                        case DestroyNotify:
                                destroyNotify(&ev);
                        break;
                        // A window is asking for configuration
            case ConfigureRequest:
                                configureRequest(&ev);
            break;
            case MapRequest:
                mapRequest(&ev);
            break;
                        // A keyboard key has been pressed
            case KeyPress:
                keyPress(&ev);
            break;
        }
    }
}


// Stop the main loop.
void WindowManager::stop(){
    m_is_running = false;
}

// Close the connection with the server
void WindowManager::quit()
{
        v_logger.log() <<  "Closing window manager..." ;
        X11::XCloseDisplay(p_display);
}



//*****************************************************************************/
//*                               EVENT HANDLERS                              */
//*****************************************************************************/


/**
* If a window has been created
*/
void WindowManager::createNotify(X11::XEvent *ev)
{
    X11::XCreateWindowEvent *we = &ev->xcreatewindow;
    //log("A window has been created");
    //WMWindow *newWindow = new WMWindow(we->window, p_display);
    //WindowCreator::getInstance()->create(we->window, p_current_screen, p_current_screen->getCurrentMonitor());
}

/**
* If a window has been destroyed
*/
void WindowManager::destroyNotify(X11::XEvent *ev)
{
    X11::XDestroyWindowEvent *we = &ev->xdestroywindow;
    //log("A window has been destroyed");

    //WindowCreator::getInstance()->destroy(we->window);
}

/**
* If a window is asking to be configured
*/
void WindowManager::configureRequest(X11::XEvent *ev)
{
    X11::XConfigureRequestEvent *we = &ev->xconfigurerequest;

    X11::XWindowChanges wc;
    wc.x = we->x;
    wc.y = we->y;
    wc.width = we->width;
    wc.height = we->height;
    wc.border_width = we->border_width;
    wc.sibling = we->above;
    wc.stack_mode = we->detail;
    XConfigureWindow(p_display, we->window, we->value_mask, &wc);
}


/**
* If a window is asking to be mapped (displayed)
*/
void WindowManager::mapRequest(X11::XEvent *ev)
{
    X11::XMapRequestEvent *we = &ev->xmaprequest;
    X11::XMapWindow(p_display, we->window);

    //WMWindow *w =
    //WindowCreator::getInstance()->get(we->window);
    //w->resize(1366,768);
    //w->move(0,0);
}


/**
* If a key has been pressed.
*/
void WindowManager::keyPress(X11::XEvent *ev)
{
    int keysym;
            int keysyms_per_keycode_return;
    X11::XKeyPressedEvent *we = &ev->xkey;

            keysym = *X11::XGetKeyboardMapping(p_display,we->keycode,1, &keysyms_per_keycode_return);

    if(keysym == XK_q)
        stop();
}
